package org.chs.ts.batch.execute;


import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.chs.ts.base.batch.exec.entity.BatchDailyBasicTaskStepExec;
import org.chs.ts.base.batch.log.entity.BatchClearBasicLog;
import org.chs.ts.base.batch.set.entity.BatchDailyBasicTaskPublish;
import org.chs.ts.base.batch.vo.entity.BatchDailyExecReq;
import org.chs.ts.base.batch.vo.entity.BatchDailyExecResp;
import org.chs.ts.base.constant.CommonConstant;
import org.chs.ts.batch.constant.TaskDailyStatusCodeEnum;
import org.chs.ts.batch.factory.SernoFactory;
import org.chs.ts.batch.factory.TaskExecFactory;
import org.chs.ts.batch.service.IBatchClearBasicLogService;
import org.chs.ts.batch.service.IBatchDailyBasicTaskStepExecService;
import org.chs.ts.batch.threadservice.BatchDailyServiceBase;
import org.chs.ts.batch.threadservice.BatchStepServiceBase;
import org.chs.ts.batch.util.ConvertToUtil;
import org.chs.ts.batch.util.EnumUtil;
import org.chs.ts.batch.exception.TaskDailyException;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * @Compay 盛唐天行
 * @Author: wuwei
 * @Censor By wuwei
 * @Sence 2023/1/10 8:59
 * @Modify 2023/1/10 8:59
 * @Description
 */
@Slf4j
@Service("BatchDailyTaskExecute")
@Scope("prototype")
public class BatchDailyTaskExecute extends BatchDailyServiceBase<BatchDailyBasicTaskPublish, BatchDailyBasicTaskStepExec> {
    // todo-wuwei：执行流程需要 优化

    private final String CLASS_NAME = this.getClass().getSimpleName();

    private static final String DEFAULT_RETURN_MSG = "执行成功！";

    @Resource
    public ApplicationContext ac;


    @Resource
    public IBatchDailyBasicTaskStepExecService taskDailyStepExecService;

    @Resource
    public IBatchClearBasicLogService clearBasicLogService;

    @Resource
    public TaskExecFactory taskExecFactory;


    private static final String SERNO_TYPE = "taskDailyStep";

    /**
     * 初始化 返回结果
     *
     * @return 返回结果对象
     */
    public BatchDailyExecResp initBatchExecResp() {
        BatchDailyBasicTaskStepExec taskDailyStepObject = this.getTaskDailyStepObject();
        BatchDailyExecResp resp = new BatchDailyExecResp();
        resp.setTaskExecid(taskDailyStepObject.getTaskExecid());
        resp.setRtnDesc(DEFAULT_RETURN_MSG);
        resp.setRtnCode(CommonConstant.RTN_CODE_SUCCESS);
        return resp;
    }

    @Override
    public BatchDailyExecResp execute(BatchDailyExecReq request) throws TaskDailyException {

        setRequest(request);
        String start = getRunningTime();
        BatchDailyExecResp resp = new BatchDailyExecResp();
        resp.setBatchSysCode(request.getBatchSysCode());
        resp.setTaskPubId(request.getTaskPubId());
        resp.setTaskExecid(request.getTaskExecid());


        BatchDailyBasicTaskPublish taskPublishObject = getTaskPublishObject();
        BatchDailyBasicTaskStepExec taskDailyStepObject = getTaskDailyStepObject();

        // 验证日间跑批任务请求表 发布状态是否为正常
        if (!taskPublishObject.getTaskPubStauts().equals(EnumUtil.日间跑批任务请求表_发布状态_发布中)) {
            getRunningTime(start);
            resp.setRtnDesc("日间跑批任务请求表[batch_daily_basic_task_publish] 跑批日间任务请求ID[" + taskPublishObject.getTaskPubId() + "]发布状态["
                    + taskPublishObject.getTaskPubStauts() + "] 日间跑批任务终止！");
            resp.setRtnCode(CommonConstant.RTN_CODE_FAILED);
            // 回写 跑批日间任务执行表 执行状态
            getStepRunningTime();
            taskDailyStepObject.setExecStatus(EnumUtil.日间跑批任务执行表_执行状态_任务终止);
            throw new TaskDailyException(resp.getRtnDesc(), TaskDailyStatusCodeEnum.TASK_RUNNING_PREERROR, this);
        }

        log.info(super.pringRunningInfo(BatchDailyTaskExecute.class.getName(), request));

        // 日间跑批任务执行
        String taskStepStartTime = getStepRunningTime();
        // 循环调用 执行步骤

        // for (BatchClearBasicTaskStepExec taskStepExec : taskStepListObject) {
        //     // 增加 对 PmcsClearBasicTaskStepExec对象 isSkip[是否跳过执行该步骤] 的支持
        //     // 针对 子步骤 为跳过执行该步骤 不予执行 直接跳过
        //
        //     if (taskStepExec.getIsSkip().equals("1")) {
        //         continue;
        //     }
        //     String taskStepStartTime = getStepRunningTime();
        //     setTaskStepObject(taskStepExec);
        //     log.info(super.pringRunningInfo(BatchDailyTaskExecute.class.getName(), taskStepExec));
        //
        //
        Class<?> serviceClass;
        try {
            serviceClass = Class.forName(taskDailyStepObject.getSliceServiceClass());
        } catch (ClassNotFoundException e) {
            // e.printStackTrace();

            resp.setRtnDesc("跑批日间任务[" + taskDailyStepObject.getStepName() + "]执行异常！" + e.getMessage());
            resp.setRtnCode(CommonConstant.RTN_CODE_FAILED);
            writeBackResult(resp, taskDailyStepObject);
            throw new TaskDailyException("跑批日间任务[" + taskDailyStepObject.getStepName() + "]执行异常！" + e.getMessage(), TaskDailyStatusCodeEnum
                    .TASK_RUNNING_ERROR, this);

        }
        BatchStepServiceBase<BatchDailyTaskExecute, BatchDailyExecResp, TaskDailyException> service = (BatchStepServiceBase) ac.getBean(serviceClass);

        try {
            service.rollback(this);
        } catch (Exception ex) {
            log.error(ex.getMessage());
            resp.setRtnDesc("跑批日间任务[" + taskDailyStepObject.getStepName() + "] rollback 执行失败！" + ex.getMessage());
            resp.setRtnCode(CommonConstant.RTN_CODE_FAILED);
            writeBackResult(resp, taskDailyStepObject);


        }
        // 跑批任务-子任务执行
        BatchDailyExecResp response;
        try {
            response = service.execute(this);
        } catch (Error | Exception ex) {
            log.error(ex.getMessage());
            resp.setRtnDesc("跑批日间任务[" + taskDailyStepObject.getStepName() + "] execute 执行失败！" + ex.getMessage());
            resp.setRtnCode(CommonConstant.RTN_CODE_FAILED);
            writeBackResult(resp, taskDailyStepObject);
            String stopTaskRunningErrMsg = "";
            try {
                taskExecFactory.stopTaskDailyRunning(taskDailyStepObject.getBatchSysCode(), taskDailyStepObject.getTaskPubId(),
                        taskDailyStepObject.getTaskExecid());
            } catch (TaskDailyException e) {
                stopTaskRunningErrMsg = e.getMessage();
            }

            throw new TaskDailyException("跑批日间任务[" + taskDailyStepObject.getStepName() + "] execute 执行失败！" + ex.getMessage() +
                    stopTaskRunningErrMsg, TaskDailyStatusCodeEnum.TASK_RUNNING_ERROR, this);

        }
        // 数据持久化
        String taskStepConsumTime = getStepRunningTime(taskStepStartTime);
        if (response.getRtnCode().equals(CommonConstant.RTN_CODE_FAILED)) {
            resp.setRtnDesc("跑批日间任务[" + taskDailyStepObject.getStepName() + "]执行失败！" + response.getRtnDesc());
            resp.setRtnCode(CommonConstant.RTN_CODE_FAILED);
            writeBackResult(resp, taskDailyStepObject);
            String stopTaskRunningErrMsg = "";
            try {
                taskExecFactory.stopTaskDailyRunning(taskDailyStepObject.getBatchSysCode(), taskDailyStepObject.getTaskPubId(),
                        taskDailyStepObject.getTaskExecid());
            } catch (TaskDailyException e) {
                stopTaskRunningErrMsg = e.getMessage();
            }
            throw new TaskDailyException("跑批子任务[" + taskDailyStepObject.getStepName() + "]执行失败！" + response.getRtnDesc() + stopTaskRunningErrMsg,
                    TaskDailyStatusCodeEnum.TASK_RUNNING_ERROR, this);
        } else {
            writeBackResult(response, taskDailyStepObject);
        }
        log.info(super.pringRunningInfo(BatchDailyTaskExecute.class.getName(), taskDailyStepObject, taskStepConsumTime));

        String taskConsumTime = getRunningTime(start);

        // 方法体 end
        log.info(super.pringRunningInfo(BatchDailyTaskExecute.class.getName(), request, taskConsumTime));


        resp.setRtnDesc("success");
        resp.setRtnCode(CommonConstant.RTN_CODE_SUCCESS);
        return writeBackResult(resp, taskDailyStepObject);
    }


    @Override
    public BatchDailyExecResp writeBackResult(BatchDailyExecResp resp, BatchDailyBasicTaskStepExec obj) {
        // 回写 taskExec 结果
        // 先回写 database 结果
        long taskStartTime = getTaskStartTime();
        getRunningTime(String.valueOf(taskStartTime));
        long taskEndTime = getTaskEndTime();
        String serverName = getPath();
        String ip = getIp();
        String port = getPort();

        obj.setExecStatus(resp.getRtnCode().equals(CommonConstant.RTN_CODE_SUCCESS) ? "3" : "4");

        try {
            if (taskDailyStepExecService.updateByObject(obj)) {
                // 更新完成 回写 redis 状态
                // taskExecFactory.updateRedisListValue(obj);
                writeBackResultForRedis(obj);
            }
        } catch (Exception e) {
            log.info("回写 batch_daily_basic_task_step_exec 异常！batch_daily_basic_task_step_exec 对象为：" + obj);

            clearBasicLogService.save(
                    ConvertToUtil.convertToV(new BatchClearBasicLog(), this.getTaskDailyStepObject(), new HashMap<String, Object>() {
                        {
                            put("logSerno", SernoFactory.createSerno(SERNO_TYPE));
                            put("batcSyCode", obj.getBatchSysCode());
                            put("stepNo", obj.getStepNo());
                            put("execStatus", "4");
                            put("shouldExecDate", obj.getExecTime());
                            put("taskExecid",obj.getTaskExecid());
                            put("targetCode", "");
                            put("startTime", ConvertToUtil.timeMillisFormatDateTime(taskStartTime));
                            put("endTime", ConvertToUtil.timeMillisFormatDateTime(taskEndTime));
                            put("threadUuid", "");
                            put("serverName", serverName);
                            put("serverIp", ip + ":" + port);
                            put("rtnCode", CommonConstant.RTN_CODE_FAILED);
                            put("rtnDesc", "回写 batch_daily_basic_task_step_exec 异常！");

                        }
                    })
            );



            resp.setRtnCode(CommonConstant.RTN_CODE_FAILED);
            resp.setRtnDesc("回写 batch_daily_basic_task_step_exec 异常！batch_daily_basic_task_step_exec 对象为：" + obj);
            return resp;


        }


        clearBasicLogService.save(
                ConvertToUtil.convertToV(new BatchClearBasicLog(), obj, new HashMap<String, Object>() {
                    {
                        put("logSerno", SernoFactory.createSerno("SERNO_TYPE"));
                        put("batcSyCode", obj.getBatchSysCode());
                        put("stepNo", obj.getStepNo());
                        put("execStatus", resp.getRtnCode().equals(CommonConstant.RTN_CODE_SUCCESS) ? "3" : "4");
                        put("shouldExecDate", "");
                        put("targetCode", "");
                        put("startTime", ConvertToUtil.timeMillisFormatDateTime(taskStartTime));
                        put("endTime", ConvertToUtil.timeMillisFormatDateTime(taskEndTime));
                        put("taskExecid",obj.getTaskExecid());
                        put("threadUuid", "");
                        put("serverName", serverName);
                        put("serverIp", ip + ":" + port);
                        put("rtnCode", CommonConstant.RTN_CODE_SUCCESS);
                        put("rtnDesc", getLogMessage(resp.getRtnDesc()));
                    }
                })
        );

        return resp;
    }



    @Override
    public void writeBackResultForRedis(BatchDailyBasicTaskStepExec obj) {
       return;
    }



    protected String getLogMessage(String msg) {
        int strLength = 1800;
        return msg.substring(0, Math.min(msg.length(), strLength));
    }

    public JSONObject getTaskParams() {

        return JSONObject.parseObject(this.getTaskDailyStepObject().getStepParams());
    }

    public String getParamsObjByKey(String key) {
        if (getTaskStepParams().containsKey(key)) {
            return getTaskStepParamsObjByKey(key);
        }
        if (getTaskParams().containsKey(key)) {
            return getTaskParamsObjByKey(key);
        }

        return "";
    }

    public List<Object> getParamsListByKey(String key) {
        if (getTaskStepParams().containsKey(key)) {
            return getTaskStepParamsListByKey(key);
        }
        if (getTaskParams().containsKey(key)) {
            return getTaskParamsListByKey(key);
        }

        return new ArrayList<>();
    }

    public String getTaskParamsObjByKey(String key) {
        return getTaskParams().getString(key);
    }

    public List<Object> getTaskParamsListByKey(String key) {
        return new ArrayList<>(getTaskParams().getJSONArray(key));
    }

    public JSONObject getTaskStepParams() {
        return JSONObject.parseObject(this.getTaskDailyStepObject().getStepParams());
    }

    public String getTaskStepParamsObjByKey(String key) {
        return getTaskStepParams().getString(key);
    }

    public List<Object> getTaskStepParamsListByKey(String key) {
        return new ArrayList<>(getTaskStepParams().getJSONArray(key));
    }


    @Override
    public BatchDailyExecResp call() {
        try {
            // 获取当前对象实例

            // 调用清算处理
            return doProcess(super.getRequest());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw e;
        }
    }


    @Override
    public BatchDailyExecResp doProcess(BatchDailyExecReq request) {
        super.doProcess(request);
        try {
            log.info("doProcess start!");
            Thread.sleep(5000);
            log.info("doProcess end!");

        } catch (InterruptedException e) {
            // e.printStackTrace();
            log.info(CLASS_NAME + " -> doProcess :" + e.getMessage());
        }

        BatchDailyExecResp resp = new BatchDailyExecResp();
        resp.setRtnDesc("success");
        resp.setRtnCode(CommonConstant.RTN_CODE_SUCCESS);

        return resp;
    }

}
